import {Color} from "../core/color";
import {ShaderProgram} from "../core/shaderProgram";
import {VertexData} from "../core/vertexData";
import {bindVAO, unbindVAO} from "../core/utils";
import {Renderer2} from "../core/renderer2";
import {mat4} from "gl-matrix";

export abstract class Material2 {

    vao: WebGLVertexArrayObject | null = null;
    posVBO: WebGLBuffer | null = null;
    indiceVBO: WebGLBuffer | null = null;

    // wireframe
    lineVAO: WebGLVertexArrayObject | null = null;
    linePosVBO:WebGLBuffer | null = null;
    lineIndiceVBO : WebGLBuffer | null = null;

    // boundingbox
    bbVAO:WebGLVertexArrayObject | null = null;
    bbPosVBO:WebGLBuffer | null = null;
    bbIndicesVBO: WebGLBuffer | null = null;

    wireFrame = true;
    static WireFrame = "wireframe";
    static WireframeColor = new Color(0x000000ff);
    static WireBoundingBoxColor = new Color(0xff0000ff);

    protected constructor(
        public vertexData:VertexData,
        public color:Color) {
        this.init()
    }

    cleanup():void{}

    init(){}

    //
    checkPosVBO(gl:WebGLRenderingContext,program:ShaderProgram){
        if (!this.posVBO){
            this.posVBO = gl.createBuffer();
            this.layoutPos(gl,program,this.vertexData.posBufferData,this.posVBO!);
        }
    }

    checkLinePosVBO(gl:WebGLRenderingContext,program:ShaderProgram){
        if (!this.linePosVBO){
            this.linePosVBO = gl.createBuffer();
            this.layoutPos(gl,program,this.vertexData.posBufferData,this.linePosVBO!);
        }
    }

    checkBBPosVBO(gl: WebGLRenderingContext, program: ShaderProgram) {
        if (!this.bbPosVBO){
            this.bbPosVBO = gl.createBuffer();
            this.layoutPos(gl,program,this.vertexData.bbPosBufferData,this.bbPosVBO!);
        }
    }

    layoutPos(gl:WebGLRenderingContext,program:ShaderProgram,bufferData:Float32Array,vbo:WebGLBuffer){
        gl.bindBuffer(gl.ARRAY_BUFFER,vbo);
        gl.bufferData(gl.ARRAY_BUFFER,bufferData,gl.STATIC_DRAW);
        let attribLocation = program.getAttribId("a_position");
        gl.enableVertexAttribArray(attribLocation);
        gl.vertexAttribPointer(attribLocation,3,gl.FLOAT,false,0,0);
    }
    checkIndiceVBO(gl:WebGLRenderingContext){
        if (!this.indiceVBO){
            this.indiceVBO = gl.createBuffer();
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,this.indiceVBO);
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,this.vertexData.indiceBufferData,gl.STATIC_DRAW);
        }
    }

    checkLineIndiceVBO(gl:WebGLRenderingContext){
        if (!this.lineIndiceVBO){
            this.lineIndiceVBO = gl.createBuffer();
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,this.lineIndiceVBO);
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,this.vertexData.lineIndicesBufferData,gl.STATIC_DRAW);
        }
    }
    checkBBIndiceVBO(gl:WebGLRenderingContext){
        if (!this.bbIndicesVBO){
            this.bbIndicesVBO = gl.createBuffer();
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,this.bbIndicesVBO);
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,this.vertexData.bbIndiceBufferData,gl.STATIC_DRAW);
        }
    }
    draw(gl:WebGLRenderingContext,projMatrix:mat4,mvMatrix:mat4){
        bindVAO(gl,this.vao!);
        gl.drawElements(gl.TRIANGLES,this.vertexData.indices.length,gl.UNSIGNED_SHORT,0);

        // TODO:可以优化成 把所有的 wireframe 最后绘制
        if (this.wireFrame){
            let program = Renderer2.instance().getProgame(Material2.WireFrame);
            program.bind();
            program.setUniformMat4("projMatrix",projMatrix);
            program.setUniformMat4("mvMatrix",mvMatrix);
            program.setUniformVec4("u_color",Material2.WireframeColor.toVec4f());
            bindVAO(gl,this.lineVAO!);
            gl.drawElements(gl.LINES,this.vertexData.lineIndicesArray.length,gl.UNSIGNED_SHORT,0);

            // 再绘bb
            program.setUniformVec4("u_color",Material2.WireBoundingBoxColor.toVec4f());
            bindVAO(gl,this.bbVAO!);
            gl.drawElements(gl.LINES,this.vertexData.bbIndiceBufferData.length,gl.UNSIGNED_SHORT,0);

            program.unbind();
        }
        unbindVAO(gl);
    }
}
